package com.example.gokchinesefoodmapmcdev.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.gokchinesefoodmapmcdev.dao.*;
import com.example.gokchinesefoodmapmcdev.entity.*;
import com.example.gokchinesefoodmapmcdev.entity.goods.*;
import com.example.gokchinesefoodmapmcdev.entity.order.OrderInfo;
import com.example.gokchinesefoodmapmcdev.entity.order.OrderNote;
import com.example.gokchinesefoodmapmcdev.entity.order.OrderSku;
import com.example.gokchinesefoodmapmcdev.entity.review.ReviewInfo;
import com.example.gokchinesefoodmapmcdev.entity.sys.SysUser;
import com.example.gokchinesefoodmapmcdev.service.GoodsService;
import com.example.gokchinesefoodmapmcdev.util.MyTranslateTools;
import com.example.gokchinesefoodmapmcdev.util.ResultData;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class GoodsServiceImpl implements GoodsService {

    @Autowired
    private GoodsInfoDAO goodsInfoDAO;

    @Autowired
    private GoodsPicDAO goodsPicDAO;

    @Autowired
    private GoodsSkuDAO goodsSkuDAO;

    @Autowired
    private MarketingPictureDAO marketingPictureDAO;

    @Autowired
    private MerchantInfoDAO merchantInfoDAO;

    @Autowired
    private GoodAttrKeyDAO goodAttrKeyDAO;

    @Autowired
    private GoodAttrValDAO goodAttrValDAO;

    @Autowired
    private ReviewInfoDAO reviewInfoDAO;

    @Autowired
    private SysUserDAO sysUserDAO;

    @Autowired
    private OrderInfoDAO orderInfoDAO;

    @Autowired
    private OrderNoteDAO orderNoteDAO;

    @Autowired
    private OrderSkuDAO orderSkuDAO;


    /**
     * 分页查询首页推荐商品信息，封装在集合中返回
     * @param pageNumber    当前页码
     * @param pageSize      一页显示数据数
     * @return
     */
    @Override
    public ResultData findRecommendGoodsInfo(Integer pageNumber, Integer pageSize) {

        // 开启分页
        PageHelper.startPage(pageNumber, pageSize);

        // 查询到所有商品信息
        List<GoodsInfo> goodsInfoList = goodsInfoDAO.selectList(null);

        List<Map<String, Object>> result = new ArrayList<>();

        if(goodsInfoList.isEmpty()){
            return ResultData.fail(ResultData.OPERATION_FAIL, "暂无商品信息");
        }
        // 根据得到的商品信息，查询其图片信息以及库存信息
        for (GoodsInfo goodsInfo : goodsInfoList) {
            // 1. 商品信息填充数据
            Map<String, Object> map = MyTranslateTools.transEntityToMap(goodsInfo);

            // 2. 填充需要的中文状态数据
            MyTranslateTools.addStatusZn(map, goodsInfo);

            // 3. 查询库存信息
            QueryWrapper<GoodsSku> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("good_id", goodsInfo.getId());
            List<Map<String, Object>> goodsSkuList = goodsSkuDAO.selectMaps(queryWrapper);
            // 库存和销量
            Integer stock = 0, sales = 0;
            if(!goodsSkuList.isEmpty()){
                for (Map<String, Object> goodsSku : goodsSkuList) {
                    stock += (Integer) goodsSku.get("stock");
                    sales += (Integer) goodsSku.get("sales");
                }
            }
            map.put("stock", stock);
            map.put("sales", sales);

            // 4. 商品图片信息（只要第一张）
            QueryWrapper<GoodsPic> queryWrapper1 = new QueryWrapper<>();
            queryWrapper.eq("good_id", goodsInfo.getId());
            List<GoodsPic> goodsPics = goodsPicDAO.selectList(queryWrapper1);
            if(goodsPics.isEmpty()){
                map.put("picture", null);
            }else {
                map.put("picture", goodsPics.get(0).getPicPath());
            }
            result.add(map);
        }

        ResultData resultData = new ResultData(ResultData.OPERATION_SUCCESS, "", result);

        return resultData;
    }

    /**
     * 查询首页的图片显示列表业务逻辑，封装在集合中返回
     * @return
     */
    @Override
    public List<MarketingPicture> findMarketingPicture() {
        List<MarketingPicture> marketingPictures = marketingPictureDAO.selectList(null);
        return marketingPictures;
    }

    @Override
    public ResultData findGoodInfoByGoodId(Integer goodId) {
        /*
            数据封装包含：1. 商品信息  2. 商品库存  3. 商品图片（list集合）
                        4. 其他信息（good_attr_key），以及其详细值(good_attr_val)
                        5. 商户信息
         */
        // 1.得到商品信息
        GoodsInfo goodsInfo = goodsInfoDAO.selectOne(new QueryWrapper<GoodsInfo>().eq("id", goodId));
        if(goodsInfo == null){
            return ResultData.fail(ResultData.OPERATION_FAIL, "查询失败");
        }
        Map<String, Object> map = MyTranslateTools.transEntityToMap(goodsInfo);

        // 2. 得到商品库存信息
        List<GoodsSku> goodsSkuList = goodsSkuDAO.selectList(new QueryWrapper<GoodsSku>().eq("good_id", goodId));
        map.put("goodSKUs", goodsSkuList);
        Integer stock = 0, sales = 0;
        BigDecimal maxPrice = null;
        BigDecimal minPrice = null;
        if(!goodsSkuList.isEmpty()) {
            maxPrice = goodsSkuList.get(0).getPrice();
            minPrice = goodsSkuList.get(0).getPrice();
            for (GoodsSku goodsSku : goodsSkuList) {
                // 找到 最高/低 价格
                maxPrice = maxPrice.max(goodsSku.getPrice());
                minPrice = minPrice.min(goodsSku.getPrice());
                // 计算库存和销售量
                if(goodsSku.getStock() != null) {
                    stock = stock + goodsSku.getStock();
                }
                if(goodsSku.getSales() != null){
                    sales = sales + goodsSku.getSales();
                }
            }
        }
        map.put("minPrice", minPrice);
        map.put("maxPrice", maxPrice);
        map.put("stock", stock);
        map.put("sales", sales);

        // 3. 得到图片信息
        List<GoodsPic> goodsPicList = goodsPicDAO.selectList(new QueryWrapper<GoodsPic>().eq("good_id", goodId));
        map.put("pictures", goodsSkuList);

        // 4. 得到商户信息
        MerchantInfo merchantInfo
                = merchantInfoDAO.selectOne(new QueryWrapper<MerchantInfo>().eq("id", goodsInfo.getMerchantId()));
        map.put("merchantLogo", merchantInfo.getMerchantLogo());
        map.put("merchantPhone", merchantInfo.getMerchantPhone());

        // 5. 发货地址应为商户地址，邮费设置为0（数据库表中没有这两个字段内容）
        map.put("shipmentPlace", merchantInfo.getMerchantAddress());
        map.put("logisticsFee", 0);
        map.put("status", merchantInfo.getStatus());

        // 6. 得到规格信息
        List<GoodAttrKey> goodAttrKeyList
                = goodAttrKeyDAO.selectList(new QueryWrapper<GoodAttrKey>().eq("good_id", goodId));
        for (GoodAttrKey goodAttrKey : goodAttrKeyList) {
            List<GoodAttrVal> goodAttrValList
                    = goodAttrValDAO.selectList(new QueryWrapper<GoodAttrVal>().eq("attr_key_id", goodAttrKey.getId()));
            goodAttrKey.setAttrValues(goodAttrValList);
        }
        map.put("speKeyValue", goodAttrKeyList);

        /*
            7. 得到评价信息（评价信息应该是一个list集合，而不是一个字段内容，需修改一下接口的返回数据？）
                    按时间倒序排列
         */
        List<ReviewInfo> reviewInfoList
                = reviewInfoDAO.selectList(new QueryWrapper<ReviewInfo>().eq("good_id", goodId).orderByDesc("gmt_create"));
        for (ReviewInfo reviewInfo : reviewInfoList) {
            // 得到评价的用户信息，一起装进去
            SysUser sysUser = sysUserDAO.selectOne(new QueryWrapper<SysUser>().eq("user_id", reviewInfo.getCustomerId()));
            reviewInfo.setSysUser(sysUser);
        }
        map.put("reviewInfo", reviewInfoList);

        ResultData resultData = new ResultData();
        resultData.put("code", ResultData.OPERATION_SUCCESS);
        resultData.put("rows", map);

        return resultData;
    }

    /**
     * 通过详情页提交订单操作（生成订单，未支付）
     *     业务要求： 1. 价格：当前规格组合单价
     *               2. 规格：用户传入规格值，若某sku商品库存为0时（不可选），这里判断，不可生成订单
     *                      用户可选多种规格，传入一个数组
     *               3. 购买数量：超过库存数量不可购买，提示“库存紧张”
     *     业务分析： 计算价格、增加订单表中数据、修改库存数量
     *     good_sku(stock对应规格的库存)
     * @param goodId    商品id
     * @param symbol    规格号
     * @param number    购买数量
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public ResultData confirmOrder(Integer goodId, Integer[] symbol, Integer number) {
        // 1. 获取需要的数据
        // 1.1 根据商品商品id、规格号数组查询 查询到规格值
        List<GoodAttrVal> goodAttrValList
                = goodAttrValDAO.selectList(new QueryWrapper<GoodAttrVal>().in("id", symbol));

        if(goodAttrValList.isEmpty()){
            return ResultData.fail(ResultData.OPERATION_FAIL, "操作失败");
        }
        // 1.2 根据得到的规格值（attr_value）和商品id一起在库存表中 查询 价格、库存
        StringBuilder attrValue = new StringBuilder();
        for (GoodAttrVal goodAttrVal : goodAttrValList) {
            // 将规格值拼接，在数据库中查询attr_symbol_text是否有对应得上的
            attrValue.append("“" + goodAttrVal.getAttrValue() + "”");
        }
        // 每种对应的规格只能有一个价格，所以应该是selectOne
        GoodsSku goodsSku = goodsSkuDAO.selectOne(new QueryWrapper<GoodsSku>().eq("attr_symbol_text", attrValue.toString()));
        // 判断库存和 用户购买数量
        if(goodsSku.getStock() < number){
            return ResultData.fail(ResultData.OPERATION_FAIL, "库存紧张");
        }

        // 1.3 价格
        BigDecimal price = goodsSku.getPrice().multiply(new BigDecimal(number));
        Date gmtCreate = new Date();
        // 1.4 商品、商户信息
        GoodsInfo goodsInfo = goodsInfoDAO.selectOne(new QueryWrapper<GoodsInfo>().eq("id", goodId));
        MerchantInfo merchantInfo = merchantInfoDAO.selectOne(new QueryWrapper<MerchantInfo>().eq("id", goodsInfo.getMerchantId()));

        // 1.5 取出用户信息
        UserDetails userDetails = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        SysUser sysUser = sysUserDAO.selectOne(new QueryWrapper<SysUser>().eq("username", userDetails.getUsername()));

        // 1.6 生成订单号
        String orderNo = getOrderNo(sysUser, gmtCreate);

        // 2. 订单信息插入
        int result = addOrderInfo(orderNo, sysUser, goodsInfo, merchantInfo, number, price, goodsSku, gmtCreate);

        // 3. 封装响应结果
        Map<String, Object> map = putOrderInfoToMap(goodsInfo, price, goodsSku, number, merchantInfo, orderNo, gmtCreate);
        ResultData resultData = new ResultData();
        if(result > 0) {
            resultData.put("code", ResultData.OPERATION_SUCCESS);
            resultData.put("rows", map);
        }else {
            resultData.put("code", ResultData.OPERATION_FAIL);
            resultData.put("msg", "出错了，请稍后再试");
        }

        return resultData;
    }

    /**
     * 订单信息封装
     */
    private Map<String, Object> putOrderInfoToMap(GoodsInfo goodsInfo, BigDecimal price, GoodsSku goodsSku, Integer number, MerchantInfo merchantInfo, String orderNo, Date gmtCreate){
        Map<String, Object> map = new HashMap<>();
        map.put("productDesc", goodsInfo.getGoodDesc());
        map.put("productName", goodsInfo.getGoodName());
        map.put("price", price);
        map.put("goodId", goodsInfo.getId());
        map.put("merchantId", goodsInfo.getMerchantId());
        map.put("skuId", goodsSku.getId());
        map.put("number", number);
        map.put("attrSymbolPath", goodsSku.getAttrSymbolPath());
        map.put("gmtCreated", gmtCreate);
        map.put("merchantName", merchantInfo.getMerchantName());
        map.put("id", orderNo);    // 订单号，
        map.put("cartId", null);    // 购物车号（从详情页提交没有购物车号）
        map.put("status", 0);    // 订单状态，刚生成订单，状态统一为未支付（0未结算，1已结算）
        return map;
    }

    /**
     * 订单信息封装和插入订单数据、修改库存和销售量
     *      此外，还需要在 订单库order_sku、订单记录order_note中 各添加一条订单信息
     */
    @Transactional(propagation = Propagation.REQUIRED)
    int addOrderInfo(String orderNo, SysUser sysUser, GoodsInfo goodsInfo, MerchantInfo merchantInfo, Integer number, BigDecimal price, GoodsSku goodsSku, Date gmtGreate){
        // 1. 订单信息封装
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setOrderNo(orderNo);
        orderInfo.setOrderSn("tr" + orderNo.substring(2));
        orderInfo.setCustomerId(sysUser.getUserId().intValue());
        orderInfo.setMerchantId(goodsInfo.getMerchantId().intValue());
        orderInfo.setMerchantName(merchantInfo.getMerchantName());
        orderInfo.setOrderStatus(0);
        orderInfo.setAfterStatus(0);
        orderInfo.setProductCount(number);
        orderInfo.setProductAmountTotal(price);
        orderInfo.setOrderAmountTotal(new BigDecimal(0));   //订单刚生成，实际还未支付，付款金额为0
        orderInfo.setLogisticsFee(new BigDecimal(0));   // 运费暂时设置为0
        orderInfo.setAddressId(0);      // 收货地址编码暂时设置为0
        orderInfo.setAdoptFinished(0);
        orderInfo.setGmtCreate(gmtGreate);
        orderInfo.setGmtUpdate(gmtGreate);

        // 2. 插入数据
        int result = orderInfoDAO.insert(orderInfo);
        // 3. 修改库存和销售量
        goodsSku.setStock(goodsSku.getStock() - number);
        goodsSku.setSales(goodsSku.getSales() + number);
        int result2 = goodsSkuDAO.updateById(goodsSku);

        // 4. 生成订单记录（插入数据到order_note中）
        OrderNote orderNote = new OrderNote();
        orderNote.setGmtCreate(gmtGreate);
        orderNote.setGmtModified(gmtGreate);
        orderNote.setOperateContend("购买");
        orderNote.setOperatePerson(sysUser.getMobile());
        orderNote.setOperatePersonId(sysUser.getUserId().intValue());
        orderNote.setOrderInfoNo(orderInfo.getOrderNo());
        int result3 = orderNoteDAO.insert(orderNote);

        // 5. 将信息存入订单库中（插入数据到order_sku中）
        OrderSku orderSku = new OrderSku();
        orderSku.setGoodId(goodsInfo.getId());
        orderSku.setGoodSkuId(goodsSku.getId());
        orderSku.setNumber(number);
        orderSku.setOrderNo(orderNo);
        // 由于子订单信息在这里没有，先设置问订单信息
        orderSku.setOrderSubAmount(price);
        orderSku.setOrderSubNo("orSub" + orderNo.substring(2));
        orderSku.setOrderSubStatus(0);
        int result4 = orderSkuDAO.insert(orderSku);

        return result4;
    }

    /**
     * 生成当前订单号
     */
    private String getOrderNo(SysUser sysUser, Date gmtCreate){
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
        StringBuilder orderNo = new StringBuilder("or");
        orderNo.append(format.format(gmtCreate));
        Integer count = orderInfoDAO.selectCount(new QueryWrapper<OrderInfo>().eq("customer_id", sysUser.getUserId()).groupBy("customer_id"));
        for(int i = 0; i < 9-count.toString().length(); i++){
            orderNo.append("0");
        }
        orderNo.append(count.toString());
        return orderNo.toString();
    }
}
